use opencv::videoio::{VideoCapture, VideoCaptureProperties};
use opencv::{prelude::*, videoio};

use crate::img;

/**
 * 获取当前视频播放的位置(ms)
 */
pub fn get_curr_pos_ms(video_cap: &VideoCapture) -> anyhow::Result<f64> {
    let pos = get_cap_prop(video_cap, VideoCaptureProperties::CAP_PROP_POS_MSEC)?;
    Ok(pos)
}

/**
 * 跳转到视频的指定位置
 * video_cap
 * ms: 指定的时间位置
 */
pub fn set_cap_pos_ms(video_cap: &mut VideoCapture, ms: f64) -> anyhow::Result<bool> {
    let res = videoio::VideoCapture::set(
        video_cap,
        VideoCaptureProperties::CAP_PROP_POS_MSEC as i32,
        ms,
    )?;
    Ok(res)
}

/**
 * 后移一帧
 */
pub fn next_frame(video_cap: &mut VideoCapture) -> anyhow::Result<bool> {
    anyhow::Ok(video_cap.grab()?)
}

/**
 * 读取一帧
 */
pub fn read_frame(video_cap: &mut VideoCapture, frame: &mut Mat) -> anyhow::Result<bool> {
    Ok(video_cap.retrieve(frame, 0)?)
}

/**
 * 打开视频
 */
pub fn open_video_cap(path: &str) -> anyhow::Result<VideoCapture> {
    let video_cap = videoio::VideoCapture::from_file(path, videoio::CAP_ANY)?;

    let opened = videoio::VideoCapture::is_opened(&video_cap)?;
    if !opened {
        anyhow::bail!("视频无法打开");
    }
    Ok(video_cap)
}

/**
 * 获取CAP值
 */
pub fn get_cap_prop(
    video_cap: &VideoCapture,
    prop_id: VideoCaptureProperties,
) -> anyhow::Result<f64> {
    let value = video_cap.get(prop_id as i32)?;
    Ok(value)
}

/**
 * 获取关键图片的位置
 */
pub fn find_img_pos_ms(
    video_path: &str,
    target_img: &str,
    start_pos: f64,
    end_pos: Option<f64>,
) -> anyhow::Result<Option<f64>> {
    let target = img::read_img_mat_from_path(target_img)?;
    let target_hash = img::img_hash_str(&target)?;

    let mut video_cap = open_video_cap(video_path)?;
    let opened = videoio::VideoCapture::is_opened(&video_cap)?;
    if !opened {
        panic!("无法打开视频文件");
    }

    // 跳过时间
    set_cap_pos_ms(&mut video_cap, start_pos)?;

    let mut frame = Mat::default();
    let mut key_vals = Vec::<(f64, f64)>::new();

    for i in 0.. {
        let grab = match video_cap.grab() {
            Err(err) => {
                eprintln!("ERR:{}", err);
                false
            }
            Ok(grab) => grab,
        };

        if !grab {
            println!("===== END ======");
            video_cap.release().unwrap();
            break;
        }

        // 每n帧处理一次
        let step_size = 5_usize;
        if i % step_size != 0 {
            continue;
        }

        read_frame(&mut video_cap, &mut frame)?;
        let hash = img::img_hash_str(&frame)?;
        let score = img::cmp_img_hash(&target_hash, &hash)?;

        let pos_ms = get_curr_pos_ms(&video_cap)?;
        // println!("每10帧处理一次. 当前时间:{}, 相似值:{}", pos_ms, score,);

        if score > 0.90f32 {
            key_vals.push((pos_ms, score as f64));
            println!("找到关键帧所在时间:{}ms", pos_ms);
            video_cap.release().unwrap();
            return Ok(Some(pos_ms));
        }

        if end_pos.is_some() && end_pos.unwrap() < pos_ms {
            video_cap.release().unwrap();
            return Ok(None);
        }
    }
    video_cap.release().unwrap();
    Ok(None)
}
